package com.tvein.system.model
{
	import flash.utils.ByteArray;
	import flash.utils.Timer;
	import flash.events.Event;
	import flash.events.TimerEvent;
	import flash.events.EventDispatcher;
	import flash.events.NetStatusEvent;
	import flash.net.NetConnection;
	import flash.net.NetGroup;
	import flash.net.NetGroupReplicationStrategy;
	import flash.net.GroupSpecifier;
//
	public class P2PFile extends EventDispatcher
	{
		public var fileSrc:String;
		public var fileVersion:String;
		public var fileData:ByteArray = null;
		public var fileChunks:Array = new Array();
		
		private var packetLenght:uint = 0;
		
		private var _rtmfpServer:String;
		private var _netConnection:NetConnection = null;
		private var _netGroup:NetGroup = null;
		
		private var _shareMode:Boolean;
		private var _startState:Boolean;
		
        public function P2PFile(rtmfpServer:String)
        {
			_rtmfpServer = rtmfpServer;
        }
		
		public function shareFile() : void
		{
			_shareMode = true;
			
			if (packetLenght == 0)
			{
				splitFile();
			}
			
			_netConnection = new NetConnection();
			_netConnection.addEventListener(NetStatusEvent.NET_STATUS, _netStatusHandler);
			_netConnection.connect(_rtmfpServer);
		}
		
		public function splitFile() : void
		{			
			packetLenght = Math.floor(fileData.length / 40000) + 1;
			
			fileChunks[0] = packetLenght + 1;
			
			for (var i:int = 1; i < packetLenght; i++)
			{
				fileChunks[i] = new ByteArray();
				fileData.readBytes(fileChunks[i], 0, 40000);
			}
			
			fileChunks[i] = new ByteArray();
			fileData.readBytes(fileChunks[i], 0, fileData.bytesAvailable);
		}
		
		public function getFile() : void
		{
			_shareMode = false;
			_netConnection = new NetConnection();
			_netConnection.addEventListener(NetStatusEvent.NET_STATUS, _netStatusHandler);
			_netConnection.connect(_rtmfpServer);
		}
		
		public function closeP2P() : void
		{
			if (_netConnection)
			{
				_netConnection.removeEventListener(NetStatusEvent.NET_STATUS, _netStatusHandler);
				_netConnection.close();
				_netConnection = null;
			}
			
			if (_netGroup)
			{
				_netGroup.removeEventListener(NetStatusEvent.NET_STATUS, _netStatusHandler);
				_netGroup.close();
				_netGroup = null;
			}
			
			fileChunks = null;
		}
		
		private function _netStatusHandler(evt:NetStatusEvent) : void
		{
			trace(evt.info.code);
			switch (evt.info.code)
			{
				case "NetConnection.Connect.Success" :
					connectGroup();
					break;
				case "NetConnection.Connect.Closed" :
					dispatchEvent(new Event(Event.CANCEL));
					break;
				case "NetConnection.Connect.Failed" :
					dispatchEvent(new Event(Event.CANCEL));
					break;
				case "NetConnection.Connect.Rejected" :
					dispatchEvent(new Event(Event.CLOSE));
					break;
				case "NetConnection.Connect.AppShutdown" :
					dispatchEvent(new Event(Event.CANCEL));
					break;
				case "NetConnection.Connect.InvalidApp" :
					dispatchEvent(new Event(Event.CANCEL));
					break;
				case "NetGroup.Connect.Success" :
					_netGroup.replicationStrategy = NetGroupReplicationStrategy.LOWEST_FIRST;
					if (_shareMode == false)
					{
						_startState = false;
						
						var checkTimer:Timer = new Timer(10000, 1);
						checkTimer.addEventListener(TimerEvent.TIMER_COMPLETE, _onTimerComplete);
						checkTimer.start();
						
						_netGroup.addWantObjects(0, 0);
					}
					else
					{
						_netGroup.addHaveObjects(0, packetLenght);
					}
					break;
				case "NetGroup.Connect.Rejected" :
					dispatchEvent(new Event(Event.CLOSE));
					break;
				case "NetGroup.Connect.Failed" :
					dispatchEvent(new Event(Event.CANCEL));
					break;
				case "NetGroup.Connect.Closed" :
					break;
				case "NetGroup.Posting.Notify" :
					break;
				case "NetGroup.SendTo.Notify" :
					break;
				case "NetGroup.LocalCoverage.Notify" :
					break;
				case "NetGroup.Neighbor.Connect" :
					break;
				case "NetGroup.Neighbor.Disconnect" :
					break;
				case "NetGroup.MulticastStream.PublishNotify" :
					break;
				case "NetGroup.MulticastStream.UnpublishNotify" :
					break;
				case "NetGroup.Replication.Fetch.SendNotify" :
					break;
				case "NetGroup.Replication.Fetch.Failed" :
					dispatchEvent(new Event(Event.CANCEL));
					break;
				case "NetGroup.Replication.Fetch.Result" :
					//作为发布者已经接收的部分
					_netGroup.addHaveObjects(evt.info.index, evt.info.index);
					
					if (evt.info.code != "NetGroup.Replication.Fetch.Result")
					{
						break;
					}
					
					//接收文件
					fileChunks[evt.info.index] = evt.info.object;
					trace("正在接收第"+evt.info.index+"块文件");
					
					if (evt.info.index == 0)
					{
						_startState = true;
						packetLenght = Number(evt.info.object);
						trace("要接收的文件有: "+ packetLenght +"块文件");
						_netGroup.addWantObjects(1, 1);
						
					}
					else
					{
						if (evt.info.index + 1 < packetLenght)
						{
							_netGroup.addWantObjects(evt.info.index + 1, evt.info.index + 1);
						}
						else
						{
							fileData = new ByteArray();
							for (var i:int = 1; i< packetLenght; i++)
							{
								fileData.writeBytes(fileChunks[i]);
							}
							
							trace("文件接收完毕，接收了: "+ packetLenght +"块文件。字节长度: "+ fileData.length);
							dispatchEvent(new Event(Event.COMPLETE));
						}
					}
					break;
				case "NetGroup.Replication.Request" :
					_netGroup.writeRequestedObject(evt.info.requestID, fileChunks[evt.info.index]);
					trace("接收方ID: "+evt.info.requestID+", 需要的文件块: "+evt.info.index);
					break;
				default :
					break;
			}
		}
		
		private function _onTimerComplete(evt:TimerEvent):void
		{
			if (_startState == false)
			{
				dispatchEvent(new Event(Event.CANCEL));
			}
			evt.target.removeEventListener(TimerEvent.TIMER_COMPLETE, _onTimerComplete);
		}
		
		private function connectGroup():void
		{
			var groupSpecifier:GroupSpecifier = new GroupSpecifier(fileSrc + "|" + fileVersion);
			groupSpecifier.multicastEnabled = true;
			groupSpecifier.postingEnabled = true;
			groupSpecifier.serverChannelEnabled = true;
			groupSpecifier.objectReplicationEnabled = true;
			
			_netGroup = new NetGroup(_netConnection,groupSpecifier.groupspecWithAuthorizations());
			_netGroup.addEventListener(NetStatusEvent.NET_STATUS, _netStatusHandler);
			
			trace("join group : " + groupSpecifier.groupspecWithAuthorizations());
		}
	}
}